import 'package:flutter/material.dart';

///none 初始, more 还有更多, noMore 没有更多了, loading 正在加载中, noData 没有数据
enum DivGridStatusEnum { none, more, noMore, loading, noData }

///列表状态
class DivGridStatus{

  const DivGridStatus({
    this.none,
    this.more,
    this.noMore,
    this.loading,
    this.noData,
    this.style = const TextStyle(fontSize: 12),
  });

  final Widget? none;
  final Widget? more;
  final Widget? noMore;
  final Widget? loading;
  final Widget? noData;
  final TextStyle style;

  ///渲染状态组件
  Widget builder(DivGridStatusEnum status) {
    if(status == DivGridStatusEnum.more){

      return more ?? Container(
        height: 30,
        alignment: Alignment.center,
        child: Text('加载更多', style: style)
      );

    }else if(status == DivGridStatusEnum.noMore){

      return noMore ?? Container(
        height: 30,
        alignment: Alignment.center,
        child: Text('没有更多了', style: style)
      );

    }else if(status == DivGridStatusEnum.loading){

      return loading ?? Container(
        height: 30,
        alignment: Alignment.center,
        child: Text('努力加载中', style: style)
      );

    }else if(status == DivGridStatusEnum.noData){

      return noData ?? Container(
        height: 30,
        alignment: Alignment.center,
        child: Text('暂无数据', style: style)
      );

    }else{
      return none ?? Container();
    }
  }
}

class DivGridData<T> {
  List<T> items = [];
  DivGridStatusEnum status = DivGridStatusEnum.none;
  int page = 0;
  ///刷新渲染组件
  void Function() refresh = (){};
  ///刷新加载数据
  Future<void> Function(bool) reload = (bool pullDown)async{};
}

class DivGrid<T> extends StatefulWidget {
  
  ///返回 false 说明没有更多数据了
  final Future<bool> Function(int page, List<T> items, bool refresh) onLoad;
  final Widget Function(BuildContext context, T item, int index) itemBuilder;
  final Widget Function(BuildContext context, List<T> items)? headerBuilder;
  final Widget Function(BuildContext context, List<T> items)? footerBuilder;
  final void Function()? init;
  final ScrollPhysics? physics;
  final bool refresh;
  final DivGridData<T>? data;
  final DivGridStatus status;
  final bool reverse;
  final bool shrinkWrap;
  final ScrollController? controller;
  final bool primary;
  final int crossCount;
  final double mainSpacing;
  final double crossSpacing;
  final double childRatio;

  const DivGrid({
    super.key,
    required this.onLoad,
    required this.itemBuilder,
    required this.crossCount,
    this.mainSpacing = 0.0,
    this.crossSpacing = 0.0,
    this.childRatio = 1.0,
    this.headerBuilder,
    this.footerBuilder,
    this.init,
    this.physics = const AlwaysScrollableScrollPhysics(),
    this.refresh = true,
    this.data,
    this.status = const DivGridStatus(),
    this.reverse = false,
    this.shrinkWrap = false,
    this.controller,
    this.primary = false,
  });
  
  @override
  createState() => _DivListState<T>();
}

class _DivListState<T> extends State<DivGrid<T>> {

  late DivGridData<T> data;

  @override
  void initState() {
    super.initState();
    data = widget.data ?? DivGridData<T>();
    data.refresh = (){
      refresh();
    };
    data.reload = (bool pullDown)async{
      await reload(pullDown);
    };
    widget.init?.call();
  }

  ///渲染页面
  void refresh() {
    if (mounted) {
      setState(() {
      });
    }
  }

  ///加载数据
  void loadMore() async {
    if (data.status != DivGridStatusEnum.none && data.status != DivGridStatusEnum.more) return;
    data.status = DivGridStatusEnum.loading;
    var more = await widget.onLoad.call(++data.page, data.items, false);
    if(data.page==1 && data.items.isEmpty && !more){
      data.status = DivGridStatusEnum.noData;
    }else if(!more) {
      data.status = DivGridStatusEnum.noMore;
    }else{
      data.status = DivGridStatusEnum.more;
    }
    refresh();
  }

  ///刷新数据
  Future<void> reload(bool pullDown) async {
    if (data.status == DivGridStatusEnum.loading) return;
    data.status == DivGridStatusEnum.more;
    var _items = <T>[];
    data.page = 1;
    var more = await widget.onLoad.call(data.page, _items, pullDown);
    if(data.page==1 && _items.isEmpty && !more){
      data.status = DivGridStatusEnum.noData;
    }else if(!more) {
      data.status = DivGridStatusEnum.noMore;
    }else{
      data.status = DivGridStatusEnum.more;
    }
    data.items = _items;
    refresh();
  }

  @override
  Widget build(BuildContext context) {

    var view = CustomScrollView(
      key: widget.key,
      shrinkWrap: widget.shrinkWrap,
      reverse: widget.reverse,
      physics: widget.physics,
      slivers:[
        widget.headerBuilder?.call(context, data.items) ?? Container(),
        SliverGrid.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: widget.crossCount,
            mainAxisSpacing: widget.mainSpacing,
            crossAxisSpacing: widget.crossSpacing,
            childAspectRatio: widget.childRatio,
          ),
          itemBuilder: _itemBuilder,
          itemCount: data.items.length,
        ),
        widget.status.builder(data.status),
        widget.footerBuilder?.call(context, data.items) ?? Container(),
      ],
    );

    if(widget.refresh){
      return RefreshIndicator(
        onRefresh: () => reload(true),
        child: view,
      );
    }else{
      return view;
    }
  }

  Widget _itemBuilder(BuildContext context, int index) {
    if(index == data.items.length - 1){
      loadMore();
    }
    return widget.itemBuilder.call(context, data.items[index], index);
  }
}
